From 99998d25f8df1bb0ac1f1624f0d33e2cbb75a79f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Timm=20B=C3=A4der?= Date: Fri, 10 Apr 2020 15:41:56 +0200 Subject: [PATCH] label: Save links in an array Stop using GList for this. --- gtk/gtklabel.c | 376 +++++++++++++++++++++++++------------------------ 1 file changed, 193 insertions(+), 183 deletions(-) diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index 992bc9cc69..3e0335b4f3 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -359,7 +359,8 @@ struct _GtkLabelSelectionInfo GtkCssNode *selection_node; GdkContentProvider *provider; - GList *links; + GtkLabelLink *links; + guint n_links; GtkLabelLink *active_link; GtkLabelLink *context_link; @@ -2026,7 +2027,7 @@ gtk_label_get_label (GtkLabel *label) typedef struct { GtkLabel *label; - GList *links; + GArray *links; GString *new_str; gsize text_len; } UriParserData; @@ -2044,7 +2045,7 @@ start_element_handler (GMarkupParseContext *context, if (strcmp (element_name, "a") == 0) { - GtkLabelLink *link; + GtkLabelLink link; const gchar *uri = NULL; const gchar *title = NULL; const gchar *class = NULL; @@ -2093,40 +2094,42 @@ start_element_handler (GMarkupParseContext *context, visited = FALSE; if (priv->track_links && priv->select_info) { - GList *l; - for (l = priv->select_info->links; l; l = l->next) + for (i = 0; i < priv->select_info->n_links; i++) { - link = l->data; - if (strcmp (uri, link->uri) == 0) + const GtkLabelLink *l = &priv->select_info->links[i]; + + if (strcmp (uri, l->uri) == 0) { - visited = link->visited; + visited = l->visited; break; } } } - link = g_new0 (GtkLabelLink, 1); - link->uri = g_strdup (uri); - link->title = g_strdup (title); + if (!pdata->links) + pdata->links = g_array_new (FALSE, TRUE, sizeof (GtkLabelLink)); + + link.uri = g_strdup (uri); + link.title = g_strdup (title); widget_node = gtk_widget_get_css_node (GTK_WIDGET (pdata->label)); - link->cssnode = gtk_css_node_new (); - gtk_css_node_set_name (link->cssnode, g_quark_from_static_string ("link")); - gtk_css_node_set_parent (link->cssnode, widget_node); + link.cssnode = gtk_css_node_new (); + gtk_css_node_set_name (link.cssnode, g_quark_from_static_string ("link")); + gtk_css_node_set_parent (link.cssnode, widget_node); if (class) - gtk_css_node_add_class (link->cssnode, g_quark_from_string (class)); + gtk_css_node_add_class (link.cssnode, g_quark_from_string (class)); state = gtk_css_node_get_state (widget_node); if (visited) state |= GTK_STATE_FLAG_VISITED; else state |= GTK_STATE_FLAG_LINK; - gtk_css_node_set_state (link->cssnode, state); - g_object_unref (link->cssnode); + gtk_css_node_set_state (link.cssnode, state); + g_object_unref (link.cssnode); - link->visited = visited; - link->start = pdata->text_len; - pdata->links = g_list_prepend (pdata->links, link); + link.visited = visited; + link.start = pdata->text_len; + g_array_append_val (pdata->links, link); } else { @@ -2165,7 +2168,7 @@ end_element_handler (GMarkupParseContext *context, if (!strcmp (element_name, "a")) { - GtkLabelLink *link = pdata->links->data; + GtkLabelLink *link = &g_array_index (pdata->links, GtkLabelLink, pdata->links->len - 1); link->end = pdata->text_len; } else @@ -2213,16 +2216,15 @@ link_free (GtkLabelLink *link) gtk_css_node_set_parent (link->cssnode, NULL); g_free (link->uri); g_free (link->title); - g_free (link); } - static gboolean -parse_uri_markup (GtkLabel *label, - const gchar *str, - gchar **new_str, - GList **links, - GError **error) +parse_uri_markup (GtkLabel *label, + const gchar *str, + gchar **new_str, + GtkLabelLink **links, + guint *out_n_links, + GError **error) { GMarkupParseContext *context = NULL; const gchar *p, *end; @@ -2268,14 +2270,25 @@ parse_uri_markup (GtkLabel *label, g_markup_parse_context_free (context); *new_str = g_string_free (pdata.new_str, FALSE); - *links = pdata.links; + + if (pdata.links) + { + *out_n_links = pdata.links->len; + *links = (GtkLabelLink *)g_array_free (pdata.links, FALSE); + } + else + { + *links = NULL; + } return TRUE; failed: g_markup_parse_context_free (context); g_string_free (pdata.new_str, TRUE); - g_list_free_full (pdata.links, (GDestroyNotify) link_free); + + if (pdata.links) + g_array_free (pdata.links, TRUE); return FALSE; } @@ -2284,12 +2297,13 @@ static void gtk_label_ensure_has_tooltip (GtkLabel *label) { GtkLabelPrivate *priv = gtk_label_get_instance_private (label); - GList *l; + guint i; gboolean has_tooltip = FALSE; - for (l = priv->select_info->links; l; l = l->next) + for (i = 0; i < priv->select_info->n_links; i++) { - GtkLabelLink *link = l->data; + const GtkLabelLink *link = &priv->select_info->links[i]; + if (link->title) { has_tooltip = TRUE; @@ -2312,9 +2326,10 @@ gtk_label_set_markup_internal (GtkLabel *label, gunichar accel_char = 0; gchar *str_for_display = NULL; gchar *str_for_accel = NULL; - GList *links = NULL; + GtkLabelLink *links = NULL; + guint n_links = 0; - if (!parse_uri_markup (label, str, &str_for_display, &links, &error)) + if (!parse_uri_markup (label, str, &str_for_display, &links, &n_links, &error)) { g_warning ("Failed to set text '%s' from markup due to error parsing markup: %s", str, error->message); @@ -2327,7 +2342,8 @@ gtk_label_set_markup_internal (GtkLabel *label, if (links) { gtk_label_ensure_select_info (label); - priv->select_info->links = g_list_reverse (links); + priv->select_info->links = g_steal_pointer (&links); + priv->select_info->n_links = n_links; _gtk_label_accessible_update_links (label); gtk_label_ensure_has_tooltip (label); gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (label)), "link"); @@ -3026,18 +3042,17 @@ gtk_label_update_layout_attributes (GtkLabel *label) if (priv->layout == NULL) return; - if (priv->select_info && priv->select_info->links) { const GdkRGBA *link_color; PangoAttribute *attribute; - GList *list; + guint i; attrs = pango_attr_list_new (); - for (list = priv->select_info->links; list; list = list->next) + for (i = 0; i < priv->select_info->n_links; i++) { - GtkLabelLink *link = list->data; + const GtkLabelLink *link = &priv->select_info->links[i]; attribute = pango_attr_underline_new (TRUE); attribute->start_index = link->start; @@ -3454,15 +3469,15 @@ static void update_link_state (GtkLabel *label) { GtkLabelPrivate *priv = gtk_label_get_instance_private (label); - GList *l; GtkStateFlags state; + guint i; if (!priv->select_info) return; - for (l = priv->select_info->links; l; l = l->next) + for (i = 0; i < priv->select_info->n_links; i++) { - GtkLabelLink *link = l->data; + const GtkLabelLink *link = &priv->select_info->links[i]; state = gtk_widget_get_state_flags (GTK_WIDGET (label)); if (link->visited) @@ -3543,26 +3558,30 @@ get_cursor_direction (GtkLabel *label) } static GtkLabelLink * -gtk_label_get_focus_link (GtkLabel *label) +gtk_label_get_focus_link (GtkLabel *label, + int *out_index) { GtkLabelPrivate *priv = gtk_label_get_instance_private (label); GtkLabelSelectionInfo *info = priv->select_info; - GList *l; + int link_index; - if (!info) - return NULL; + if (!info || + info->selection_anchor != info->selection_end) + goto nope; - if (info->selection_anchor != info->selection_end) - return NULL; + link_index = _gtk_label_get_link_at (label, info->selection_anchor); - for (l = info->links; l; l = l->next) + if (link_index != -1) { - GtkLabelLink *link = l->data; - if (link->start <= info->selection_anchor && - info->selection_anchor <= link->end) - return link; + if (out_index) + *out_index = link_index; + + return &info->links[link_index]; } +nope: + if (out_index) + *out_index = -1; return NULL; } @@ -3652,7 +3671,7 @@ gtk_label_snapshot (GtkWidget *widget, cursor_direction); } - focus_link = gtk_label_get_focus_link (label); + focus_link = gtk_label_get_focus_link (label, NULL); active_link = info->active_link; if (active_link) @@ -3974,8 +3993,6 @@ gtk_label_grab_focus (GtkWidget *widget) GtkLabel *label = GTK_LABEL (widget); GtkLabelPrivate *priv = gtk_label_get_instance_private (label); gboolean select_on_focus; - GtkLabelLink *link; - GList *l; if (priv->select_info == NULL) return FALSE; @@ -3997,9 +4014,12 @@ gtk_label_grab_focus (GtkWidget *widget) { if (priv->select_info->links && !priv->in_click) { - for (l = priv->select_info->links; l; l = l->next) + guint i; + + for (i = 0; i < priv->select_info->n_links; i++) { - link = l->data; + const GtkLabelLink *link = &priv->select_info->links[i]; + if (!range_is_in_ellipsis (label, link->start, link->end)) { priv->select_info->selection_anchor = link->start; @@ -4022,19 +4042,19 @@ gtk_label_focus (GtkWidget *widget, GtkLabelPrivate *priv = gtk_label_get_instance_private (label); GtkLabelSelectionInfo *info = priv->select_info; GtkLabelLink *focus_link; - GList *l; if (!gtk_widget_is_focus (widget)) { gtk_widget_grab_focus (widget); if (info) { - focus_link = gtk_label_get_focus_link (label); + focus_link = gtk_label_get_focus_link (label, NULL); if (focus_link && direction == GTK_DIR_TAB_BACKWARD) { - for (l = g_list_last (info->links); l; l = l->prev) + int i; + for (i = info->n_links - 1; i >= 0; i--) { - focus_link = l->data; + focus_link = &info->links[i]; if (!range_is_in_ellipsis (label, focus_link->start, focus_link->end)) { info->selection_anchor = focus_link->start; @@ -4063,54 +4083,63 @@ gtk_label_focus (GtkWidget *widget, index = info->selection_anchor; if (direction == GTK_DIR_TAB_FORWARD) - for (l = info->links; l; l = l->next) - { - GtkLabelLink *link = l->data; + { + guint i; + for (i = 0; i < info->n_links; i++) + { + const GtkLabelLink *link = &info->links[i]; - if (link->start > index) - { - if (!range_is_in_ellipsis (label, link->start, link->end)) - { - gtk_label_select_region_index (label, link->start, link->start); - _gtk_label_accessible_focus_link_changed (label); - return TRUE; - } - } - } + if (link->start > index) + { + if (!range_is_in_ellipsis (label, link->start, link->end)) + { + gtk_label_select_region_index (label, link->start, link->start); + _gtk_label_accessible_focus_link_changed (label); + return TRUE; + } + } + } + } else if (direction == GTK_DIR_TAB_BACKWARD) - for (l = g_list_last (info->links); l; l = l->prev) - { - GtkLabelLink *link = l->data; + { + int i; + for (i = info->n_links - 1; i >= 0; i--) + { + GtkLabelLink *link = &info->links[i]; - if (link->end < index) - { - if (!range_is_in_ellipsis (label, link->start, link->end)) - { - gtk_label_select_region_index (label, link->start, link->start); - _gtk_label_accessible_focus_link_changed (label); - return TRUE; - } - } - } + if (link->end < index) + { + if (!range_is_in_ellipsis (label, link->start, link->end)) + { + gtk_label_select_region_index (label, link->start, link->start); + _gtk_label_accessible_focus_link_changed (label); + return TRUE; + } + } + } + } goto out; } else { - focus_link = gtk_label_get_focus_link (label); + int focus_link_index; + int new_index = -1; + int i; + + focus_link = gtk_label_get_focus_link (label, &focus_link_index); + switch (direction) { case GTK_DIR_TAB_FORWARD: if (focus_link) - { - l = g_list_find (info->links, focus_link); - l = l->next; - } + new_index = (focus_link_index + 1) % info->n_links; else - l = info->links; - for (; l; l = l->next) + new_index = 0; + + for (i = new_index; i < info->n_links; i++) { - GtkLabelLink *link = l->data; + const GtkLabelLink *link = &info->links[i]; if (!range_is_in_ellipsis (label, link->start, link->end)) break; } @@ -4118,15 +4147,13 @@ gtk_label_focus (GtkWidget *widget, case GTK_DIR_TAB_BACKWARD: if (focus_link) - { - l = g_list_find (info->links, focus_link); - l = l->prev; - } + new_index = focus_link_index == 0 ? info->n_links - 1 : focus_link_index - 1; else - l = g_list_last (info->links); - for (; l; l = l->prev) + new_index = info->n_links - 1; + + for (i = new_index; i >= 0; i--) { - GtkLabelLink *link = l->data; + const GtkLabelLink *link = &info->links[i]; if (!range_is_in_ellipsis (label, link->start, link->end)) break; } @@ -4140,9 +4167,9 @@ gtk_label_focus (GtkWidget *widget, goto out; } - if (l) + if (new_index != -1) { - focus_link = l->data; + focus_link = &info->links[new_index]; info->selection_anchor = focus_link->start; info->selection_end = focus_link->start; _gtk_label_accessible_focus_link_changed (label); @@ -4514,7 +4541,6 @@ gtk_label_update_active_link (GtkWidget *widget, if (info->links && !info->in_drag) { - GList *l; GtkLabelLink *link; gboolean found = FALSE; @@ -4522,15 +4548,14 @@ gtk_label_update_active_link (GtkWidget *widget, { if (get_layout_index (label, x, y, &index)) { - for (l = info->links; l != NULL; l = l->next) + const int link_index = _gtk_label_get_link_at (label, index); + + if (link_index != -1) { - link = l->data; - if (index >= link->start && index <= link->end) - { - if (!range_is_in_ellipsis (label, link->start, link->end)) - found = TRUE; - break; - } + link = &info->links[link_index]; + + if (!range_is_in_ellipsis (label, link->start, link->end)) + found = TRUE; } } } @@ -5604,7 +5629,7 @@ gtk_label_copy_clipboard (GtkLabel *label) { GtkLabelLink *link; - link = gtk_label_get_focus_link (label); + link = gtk_label_get_focus_link (label, NULL); if (link) gdk_clipboard_set_text (clipboard, link->uri); } @@ -5626,7 +5651,7 @@ gtk_label_activate_link_open (GtkWidget *widget, { GtkLabel *label = GTK_LABEL (widget); GtkLabelPrivate *priv = gtk_label_get_instance_private (label); - GtkLabelLink *link = priv->select_info->context_link; + GtkLabelLink *link = priv->select_info->context_link; if (link) emit_activate_link (label, link); @@ -5691,7 +5716,7 @@ gtk_label_update_actions (GtkLabel *label) else { has_selection = FALSE; - link = gtk_label_get_focus_link (label); + link = gtk_label_get_focus_link (label, NULL); } gtk_widget_action_set_enabled (widget, "clipboard.copy", has_selection); @@ -5754,7 +5779,7 @@ gtk_label_do_popup (GtkLabel *label, if (priv->select_info->link_clicked) priv->select_info->context_link = priv->select_info->active_link; else - priv->select_info->context_link = gtk_label_get_focus_link (label); + priv->select_info->context_link = gtk_label_get_focus_link (label, NULL); gtk_label_update_actions (label); @@ -5798,12 +5823,16 @@ static void gtk_label_clear_links (GtkLabel *label) { GtkLabelPrivate *priv = gtk_label_get_instance_private (label); + guint i; if (!priv->select_info) return; - g_list_free_full (priv->select_info->links, (GDestroyNotify) link_free); + for (i = 0; i < priv->select_info->n_links; i++) + link_free (&priv->select_info->links[i]); + g_free (priv->select_info->links); priv->select_info->links = NULL; + priv->select_info->n_links = 0; priv->select_info->active_link = NULL; gtk_style_context_remove_class (gtk_widget_get_style_context (GTK_WIDGET (label)), "link"); @@ -5856,7 +5885,7 @@ gtk_label_activate_current_link (GtkLabel *label) GtkLabelLink *link; GtkWidget *widget = GTK_WIDGET (label); - link = gtk_label_get_focus_link (label); + link = gtk_label_get_focus_link (label, NULL); if (link) emit_activate_link (label, link); @@ -5876,7 +5905,7 @@ gtk_label_get_current_link (GtkLabel *label) if (priv->select_info->link_clicked) link = priv->select_info->active_link; else - link = gtk_label_get_focus_link (label); + link = gtk_label_get_focus_link (label, NULL); return link; } @@ -5970,7 +5999,6 @@ gtk_label_query_tooltip (GtkWidget *widget, GtkLabelPrivate *priv = gtk_label_get_instance_private (label); GtkLabelSelectionInfo *info = priv->select_info; gint index = -1; - GList *l; if (info && info->links) { @@ -5987,17 +6015,15 @@ gtk_label_query_tooltip (GtkWidget *widget, if (index != -1) { - for (l = info->links; l != NULL; l = l->next) + const int link_index = _gtk_label_get_link_at (label, index); + + if (link_index != -1) { - GtkLabelLink *link = l->data; - if (index >= link->start && index <= link->end) + const GtkLabelLink *link = &info->links[link_index]; + + if (link->title) { - if (link->title) - { - gtk_tooltip_set_markup (tooltip, link->title); - return TRUE; - } - break; + gtk_tooltip_set_markup (tooltip, link->title); } } } @@ -6085,7 +6111,7 @@ _gtk_label_get_n_links (GtkLabel *label) GtkLabelPrivate *priv = gtk_label_get_instance_private (label); if (priv->select_info) - return g_list_length (priv->select_info->links); + return priv->select_info->n_links; return 0; } @@ -6097,11 +6123,7 @@ _gtk_label_get_link_uri (GtkLabel *label, GtkLabelPrivate *priv = gtk_label_get_instance_private (label); if (priv->select_info) - { - GtkLabelLink *link = g_list_nth_data (priv->select_info->links, idx); - if (link) - return link->uri; - } + return priv->select_info->links[idx].uri; return NULL; } @@ -6113,42 +6135,39 @@ _gtk_label_get_link_extent (GtkLabel *label, gint *end) { GtkLabelPrivate *priv = gtk_label_get_instance_private (label); - gint i; - GList *l; - GtkLabelLink *link; if (priv->select_info) - for (l = priv->select_info->links, i = 0; l; l = l->next, i++) - { - if (i == idx) - { - link = l->data; - *start = link->start; - *end = link->end; - return; - } - } + { + const GtkLabelLink *link = &priv->select_info->links[idx]; - *start = -1; - *end = -1; + *start = link->start; + *end = link->end; + } + else + { + *start = -1; + *end = -1; + } } -gint -_gtk_label_get_link_at (GtkLabel *label, - gint pos) +int +_gtk_label_get_link_at (GtkLabel *label, + int pos) { GtkLabelPrivate *priv = gtk_label_get_instance_private (label); - gint i; - GList *l; - GtkLabelLink *link; if (priv->select_info) - for (l = priv->select_info->links, i = 0; l; l = l->next, i++) - { - link = l->data; - if (link->start <= pos && pos < link->end) - return i; - } + { + guint i; + + for (i = 0; i < priv->select_info->n_links; i++) + { + const GtkLabelLink *link = &priv->select_info->links[i]; + + if (link->start <= pos && pos < link->end) + return i; + } + } return -1; } @@ -6161,10 +6180,9 @@ _gtk_label_activate_link (GtkLabel *label, if (priv->select_info) { - GtkLabelLink *link = g_list_nth_data (priv->select_info->links, idx); + GtkLabelLink *link = &priv->select_info->links[idx]; - if (link) - emit_activate_link (label, link); + emit_activate_link (label, link); } } @@ -6175,10 +6193,7 @@ _gtk_label_get_link_visited (GtkLabel *label, GtkLabelPrivate *priv = gtk_label_get_instance_private (label); if (priv->select_info) - { - GtkLabelLink *link = g_list_nth_data (priv->select_info->links, idx); - return link ? link->visited : FALSE; - } + return priv->select_info->links[idx].visited; return FALSE; } @@ -6188,9 +6203,6 @@ _gtk_label_get_link_focused (GtkLabel *label, gint idx) { GtkLabelPrivate *priv = gtk_label_get_instance_private (label); - gint i; - GList *l; - GtkLabelLink *link; GtkLabelSelectionInfo *info = priv->select_info; if (!info) @@ -6199,15 +6211,13 @@ _gtk_label_get_link_focused (GtkLabel *label, if (info->selection_anchor != info->selection_end) return FALSE; - for (l = info->links, i = 0; l; l = l->next, i++) + if (idx >= 0 && idx < info->n_links) { - if (i == idx) - { - link = l->data; - if (link->start <= info->selection_anchor && - info->selection_anchor <= link->end) - return TRUE; - } + const GtkLabelLink *link = &info->links[idx]; + + if (link->start <= info->selection_anchor && + info->selection_anchor <= link->end) + return TRUE; } return FALSE; -- 2.30.2